package com.example.demo.lunar.utils;

import com.example.demo.lunar.entity.SolarTermInfo;
import com.nlf.calendar.Lunar;
import com.nlf.calendar.Solar;

import java.time.LocalDate;
import java.time.ZoneId;
import java.util.*;

/**
 * @author LHH
 * @date 2025/7/1
 */
public class LunarDateUtil {

    /**
     * 获取指定日期相关的二十四节气信息(农历年)
     *
     * @param date 公历日期，格式为"yyyy-MM-dd"
     * @return 二十四节气信息列表（按公历日期排序）
     * PS: 因根据春节为切分线,导致[农历年]可能部分数据为 23节气(缺少立春) 或者 25节气(多一个立春),每年春节当天会更新全部节气日期
     */
    public static List<SolarTermInfo> getLunarYearSolarTerms(Date date) {
        // 解析输入日期
        LocalDate newDate = date.toInstant()
                .atZone(ZoneId.systemDefault())
                .toLocalDate();

        int year = newDate.getYear();
        int month = newDate.getMonthValue();
        int day = newDate.getDayOfMonth();

        // 获取指定日期的农历信息
        Solar solar = new Solar(year, month, day);
        Lunar lunar = solar.getLunar();

        // 确定基准农历年
        int baseLunarYear = lunar.getYear();

        // 检查是否在农历新年前
        Solar baseYearFirstDay = new Lunar(baseLunarYear, 1, 1).getSolar();
        if (solar.toYmd().compareTo(baseYearFirstDay.toYmd()) < 0) {
            baseLunarYear--;
        }

        // 获取该农历年的二十四节气信息
        return getSolarTermsForLunarYear(baseLunarYear);
    }

    /**
     * 获取指定农历年的二十四节气信息
     *
     * @param lunarYear 农历年
     * @return 二十四节气信息列表
     */
    private static List<SolarTermInfo> getSolarTermsForLunarYear(int lunarYear) {
        // 计算农历年的公历起止日期
        Solar startSolar = new Lunar(lunarYear, 1, 1).getSolar();
        Solar endSolar = new Lunar(lunarYear + 1, 1, 1).getSolar().next(-1);

        // 收集该范围内的节气
        List<SolarTermInfo> solarTerms = new ArrayList<>();
        Solar current = startSolar;

        // 遍历整个农历年（最多400天）
        while (current.toYmd().compareTo(endSolar.toYmd()) <= 0) {
            // 获取当天的农历信息
            Lunar currentLunar = current.getLunar();

            // 检查是否是节气
            String jieQi = currentLunar.getJieQi();
            if (jieQi != null && !jieQi.isEmpty()) {
                // 创建节气信息对象
                SolarTermInfo info = new SolarTermInfo(
                        jieQi,
                        current.getYear(),
                        current.getMonth(),
                        current.getDay(),
                        currentLunar.getYearInGanZhi(),   // 年干支
                        currentLunar.getMonthInChinese(),  // 农历月
                        currentLunar.getDayInChinese(),     // 农历日
                        null
                );
                solarTerms.add(info);
            }

            // 移动到下一天
            current = current.next(1);
        }

        // 按公历日期排序
        Collections.sort(solarTerms, new Comparator<SolarTermInfo>() {
            @Override
            public int compare(SolarTermInfo o1, SolarTermInfo o2) {
                if (o1.getSolarYear() != o2.getSolarYear()) {
                    return Integer.compare(o1.getSolarYear(), o2.getSolarYear());
                }
                if (o1.getSolarMonth() != o2.getSolarMonth()) {
                    return Integer.compare(o1.getSolarMonth(), o2.getSolarMonth());
                }
                return Integer.compare(o1.getSolarDay(), o2.getSolarDay());
            }
        });

        return solarTerms;
    }

    /**
     * 获取指定年份的所有节气信息(阳历年)
     *
     * @param date 公历日期，格式为"yyyy-MM-dd"
     * @return 该阳历年内的节气信息列表（按公历日期排序）
     * PS:[阳历年]不会出现双节气,但是会出现跨农历年的节气,每年都1月1日会更新全部节气日期
     */
    public static List<SolarTermInfo> getSolarTermsBySolarYear(Date date) {
// 解析输入日期
        LocalDate newDate = date.toInstant()
                .atZone(ZoneId.systemDefault())
                .toLocalDate();

        int solarYear = newDate.getYear();
        // 创建该年的第一天
        Solar start = new Solar(solarYear, 1, 1);
        // 创建该年的最后一天
        Solar end = new Solar(solarYear, 12, 31);

        // 收集该年的节气
        List<SolarTermInfo> solarTerms = new ArrayList<>();
        Solar current = start;

        // 遍历全年每一天
        while (current.toYmd().compareTo(end.toYmd()) <= 0) {
            // 获取当天的农历信息
            Lunar currentLunar = current.getLunar();

            // 检查是否是节气
            String jieQi = currentLunar.getJieQi();
            if (jieQi != null && !jieQi.isEmpty()) {
                // 计算该日期是一年中的第几天
                int dayOfYear = calculateDayOfYear(current);

                // 创建节气信息对象
                SolarTermInfo info = new SolarTermInfo(
                        jieQi,
                        current.getYear(),
                        current.getMonth(),
                        current.getDay(),
                        currentLunar.getYearInGanZhi(),   // 年干支
                        currentLunar.getMonthInChinese(), // 农历月
                        currentLunar.getDayInChinese(),   // 农历日
                        dayOfYear                         // 一年中的第几天
                );
                solarTerms.add(info);
            }

            // 移动到下一天
            current = current.next(1);
        }

        // 按公历日期排序
        Collections.sort(solarTerms, new Comparator<SolarTermInfo>() {
            @Override
            public int compare(SolarTermInfo o1, SolarTermInfo o2) {
                return Integer.compare(o1.getDayOfYear(), o2.getDayOfYear());
            }
        });

        return solarTerms;
    }

    /**
     * 计算指定日期是该年的第几天
     *
     * @param solar 日期对象
     * @return 该年的第几天（1-366）
     */
    private static int calculateDayOfYear(Solar solar) {
        int[] daysInMonth = {0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};

        // 处理闰年（2月有29天）
        int year = solar.getYear();
        if ((year % 4 == 0 && year % 100 != 0) || (year % 400 == 0)) {
            daysInMonth[2] = 29;
        }

        int dayOfYear = 0;
        // 累加前几个月的天数
        for (int month = 1; month < solar.getMonth(); month++) {
            dayOfYear += daysInMonth[month];
        }
        // 加上当月的天数
        dayOfYear += solar.getDay();

        return dayOfYear;
    }

}
